/* 
Original Code 
Copyright (c) 2005, CRPlugin Developers
All rights reserved.
http://sourceforge.net/projects/crplugin/

 
 c# Conversion and change to Generics By Chris Rickard 7/30/2007
 */

using System;
using System.Collections.Generic;
using System.Text;

namespace ScintillaNet
{
	using System;
	using System.Windows.Forms;

	public enum CycleDirection
	{
		Forward,
		Backward
	}

	public class Ring<T>
	{
		protected int _capacity = 50;
		protected int _currentIndex = -1;
		protected int _newestIndex = -1;
		protected int _oldestIndex = -1;
		protected int _count = 0;
		protected T[] _entries;

		public bool IsFull
		{
			get { return _count >= _capacity; }
		}

		public int Count
		{
			get { return _count; }
		}

		public int BufferNumber
		{
			get
			{
				if (_currentIndex < 0)
				{
					return -1;
				}
					
				int l_Index = _currentIndex;
				int l_BufferNum = 0;

				while (l_Index != _newestIndex)
				{
					MoveIndexForward(ref l_Index);
					l_BufferNum += 1;
					if (l_BufferNum > _capacity)
						break; 
				}

				return l_BufferNum;
			}
		}

		public T CurrentEntry
		{
			get
			{
				return _entries[_currentIndex];
			}
		}

		
		public Ring()
		{
			_entries = (T[])Array.CreateInstance(typeof(T), _capacity);
		}

		public Ring(int capacity)
		{

			_capacity = capacity;
			_entries = (T[])Array.CreateInstance(typeof(T), capacity);
		}

		public void Clear()
		{
			_currentIndex = -1;
			_newestIndex = -1;
			_oldestIndex = -1;
			_count = 0;
			_entries = (T[])Array.CreateInstance(typeof(T), _capacity);
		}

		private void MoveIndexForward(ref int index)
		{
			index += 1;
			if (index >= _capacity)
				index = 0;
		}

		private void RemoveOldestEntry()
		{
			MoveIndexForward(ref _oldestIndex);

			if (_count > 0)
			{
				_count -= 1;
			}
			else
			{
				_oldestIndex = -1;
				_newestIndex = -1;
			}
		}

		private void AddNewEntry(T obj)
		{
			MoveIndexForward(ref _newestIndex);
			_entries[_newestIndex] = obj;

			if (_oldestIndex < 0)
				_oldestIndex = 0;

			if (_count < _capacity)
				_count += 1;

			_currentIndex = _newestIndex;
		}

		private void CycleForward()
		{
			_currentIndex += 1;

			if (_newestIndex >= _oldestIndex)
			{
				if (_currentIndex > _newestIndex)
					_currentIndex = _oldestIndex;
			}
			else
			{
				if (_currentIndex >= _capacity)
					_currentIndex = 0;
			}
		}

		private void CycleBackward()
		{
			_currentIndex -= 1;

			if (_newestIndex >= _oldestIndex)
			{
				if (_currentIndex < _oldestIndex)
					_currentIndex = _newestIndex;
			}
			else
			{
				if (_currentIndex < 0)
					_currentIndex = _capacity - 1;
			}
		}

		public void Add(T obj)
		{
			if (IsFull)
				RemoveOldestEntry();

			AddNewEntry(obj);
		}

		public void Cycle(CycleDirection Direction)
		{
			if (Direction == CycleDirection.Forward)
				CycleForward();
			else
				CycleBackward();
		}
	}
}
